package 多线程;

import java.util.concurrent.locks.Lock;

/*public class Test {
	public static void main(String[]args) {
		RunnableDemo R1=new RunnableDemo("Thread-1");
		R1.start1();

		RunnableDemo R2=new RunnableDemo("Thread-2");
		R2.start1();
	}
}
class RunnableDemo implements Runnable {
	private Thread t;
	private String threadName;
	public RunnableDemo(String Name) {
		threadName=Name;
		System.out.println("creating "+threadName);
	}
	public void run() {
		System.out.println("Runing "+threadName);
		try {
			for (int i=4;i>0;i--) {
				System.out.println("Thread: "+threadName+", "+i);
				Thread.sleep(10);
			}
				
		}catch(InterruptedException e){
			System.out.println("Thread:"+threadName+"Interrupted");
		}
		System.out.println("Thread:"+threadName+"exiting");
	}
	public void start1() {
		System.out.println("Starting "+threadName);
		if(t==null) {
			t=new Thread(this,threadName);
			t.start();
		}
	}
}*/

//通过实现 Runnable 接口创建线程
/*class DisplayMessage implements Runnable {
	private String message;

	public DisplayMessage(String message) {
		this.message = message;
	}

	public void run() {
		while (true) {
			System.out.println(message);
		}
	}
}

//通过继承 Thread 类创建线程
class GuessANumber extends Thread {
	private int number;

	public GuessANumber(int number) {
		this.number = number;
	}

	public void run() {
		int counter = 0;
		int guess = 0;
		do {
			guess = (int) (Math.random() * 100 + 1);
			System.out.println(this.getName() + " guesses " + guess);
			counter++;
		} while (guess != number);
		System.out.println("** Correct!" + this.getName() + "in" + counter + "guesses.**"+"-->"+number);
	}
}

//public class ThreadClassDemo {
public class Test {

	public static void main(String[] args) {
		Runnable hello = new DisplayMessage("Hello");
		Thread thread1 = new Thread(hello);
		thread1.setDaemon(true);
		thread1.setName("hello");
		System.out.println("Starting hello thread...");
		thread1.start();

		Runnable bye = new DisplayMessage("Goodbye");
		Thread thread2 = new Thread(bye);
		thread2.setPriority(Thread.MIN_PRIORITY);
		thread2.setDaemon(true);
		System.out.println("Starting goodbye thread...");
		thread2.start();

		System.out.println("Starting thread3...");
		Thread thread3 = new GuessANumber(27);
		thread3.start();
		try {
			thread3.join();
		} catch (InterruptedException e) {
			System.out.println("Thread interrupted.");
		}
		System.out.println("Starting thread4...");
		Thread thread4 = new GuessANumber(75);

		thread4.start();
		System.out.println("main() is ending...");
	}
}*/

/*import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class Test implements Callable<String>{

	public static void main(String[] args) {
//		ExecutorService threadPool=Executors.newSingleThreadExecutor();
		ExecutorService threadPool=Executors.newFixedThreadPool(1);
		Future<String> future=threadPool.submit(new Test());
		try {
			System.out.println("sadasdas");
			System.out.println(future.get());
		}catch(Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	public String call() throws Exception {
		// TODO 自动生成的方法存根
		return "创建线程";
	}
}*/

//import java.util.concurrent.ExecutorService;
//import java.util.concurrent.Executors;
////public class CachedThreadPoolTest {
//public class Test {
//	public static void main(String[] args) {
//		// 获取 ExecutorService 实例可以利用 JDK 中的 Executors 类中的静态方法
//		ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
//
//		// 提交10个任务给线程池，每个任务输出自己的索引
//		for (int i = 0; i < 10; i++) {
//			final int index = i;
//			Runnable task = new Runnable() {
//				public void run() {
//					try {
//						Thread.sleep(1000);
//					} catch (InterruptedException e) {
//						e.printStackTrace();
//					}
//					System.out.println(Thread.currentThread().getName() + ">>" + index);
//				}
//			};
//			// 提交任务
//			cachedThreadPool.execute(task);
//		}
//		// 关闭线程池
//		cachedThreadPool.shutdown();
//	}
//}

//public class ThreadGetId {
//public class Test {
//
//    public static void run(String tag) {
//        Thread thread = Thread.currentThread();
//        System.out.println(tag + " 的线程ID: " + thread.getId());
//    }
//
//    public static void main(String[] args) {
//
//        Thread thread1 = new Thread(() -> {run("线1");});
//        System.out.println("线1的线程ID: " + thread1.getId());
//        thread1.start();
//
//        new Thread(() -> {run("线2");}).start();
//
//        String tag = "主";
//        Thread current = Thread.currentThread();
//        System.out.println(tag + " 的线程ID: " + current.getId());
//        run(tag);
//
//    }
//}
//@FunctionalInterface
//interface Runnable {
//    public abstract void run();
//}
//public Thread(Runnable target) {
//    this(null, target, "Thread-" + nextThreadNum(), 0);
//}
//import java.util.concurrent.ExecutorService;
//import java.util.concurrent.Executors;
//
//public class Test {
//	public static void run(String index) {
//		try {//执行一个线程用1秒，故多个线程完成多个任务
//			Thread.sleep(1000);
//		} catch (InterruptedException e) {
//			e.printStackTrace();
//		}
//		System.out.println(Thread.currentThread().getName() + ">>" + index);
//	}
//
//	public static void main(String[] args) {
//
//		ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
//		// 提交10个任务给线程池，每个任务输出自己的索引
//		for (int i = 0; i < 10; i++) {
//			final int index = i;
////			try {//执行一个任务用1秒，故一个线程完成多个任务
////				Thread.sleep(1000);
////			} catch (InterruptedException e) {
////				e.printStackTrace();
////			}
//
//			// 提交任务
//			cachedThreadPool.execute(() -> run("" + index));
//		}
//		// 关闭线程池
//		cachedThreadPool.shutdown();
//	}
//}

/*import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

//public class FixedThreadPoolTest {
public class Test {
	public static void main(String[] args) {

		ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);

		// 向线程池提交9个任务，每个任务输出对应的索引
		for (int i = 0; i < 9; i++) {
			final int index = i;
			fixedThreadPool.execute(new Runnable() {
				public void run() {
					try {
						System.out.println(Thread.currentThread().getName() + ">>" + index);
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			});
		}
		// 关闭线程池
		fixedThreadPool.shutdown();
	}
}*/

/*public class Test{
	public static void main(String[] args) throws InterruptedException {
		var dec=new DecThread();
		var add=new AddThread();
		add.start();
		dec.start();
		add.join();
		dec.join();
		System.out.println(Counter.count);
	}
}
class Counter{
	public static final Object lock=new Object();
	public static int count=0;
}

class AddThread extends Thread{
	public void run() {
		for (int i=0;i<100000;i++) {
			synchronized(Counter.lock) {Counter.count+=i;}
		}
	}
}

class DecThread extends Thread{
	public void run() {
		for (int i=0;i<100000;i++) {
			synchronized(Counter.lock) {Counter.count-=i;}
		}
	}
}*/

/*public class Test{
	public static void main(String[] args) throws Exception {
		var c1=new Cter();
//		var c2=new Cter();
		Thread th1=new Thread(() -> { c1.add(100);});
		Thread th2=new Thread(() -> { c1.dec(100);});
		th1.start();
		th2.start();
		th1.join();
		th2.join();
		System.out.println(c1.get());
	}
}
class Cter {
    private int count = 0;

    public void add(int n) {
        synchronized(this) {
            count += n;
        }
    }

    public void dec(int n) {
        synchronized(this) {
            count -= n;
        }
    }

    public int get() {
        return count;
    }
}*/

//死锁
/*public class Test{
	static final Object Lock_A=new Object();
	static final Object Lock_B=new Object();
	static void sleep1s() {
		try {
			Thread.sleep(1000);
		}catch (InterruptedException e){
			e.printStackTrace();
		}
	}
	public static void main(String[] args) throws Exception {
		Thread t1=new Thread1();
		t1.start();
		Thread t2=new Thread2();
		t2.start();
		t1.join();
		t2.join();
	}
}

class Thread1 extends Thread {
	public void run(){
		System.out.println("Thread1尝试获得锁：Lock_A");
		synchronized(Test.Lock_A) {
			System.out.println("Thread1获得锁：Lock_A");
//			Test.sleep1s();
			System.out.println("Thread1尝试获得锁：Lock_B");
			synchronized(Test.Lock_B) {
				System.out.println("Thread1获得锁：Lock_B");
//				Test.sleep1s();
			}
			System.out.println("Thread1：Lock_B释放");
		}
		System.out.println("Thread1：Lock_A释放");
	}
}

class Thread2 extends Thread{
	public void run(){
		System.out.println("Thread2尝试获得锁：Lock_A");
		synchronized(Test.Lock_A) {
			System.out.println("Thread2获得锁：Lock_A");
//			Test.sleep1s();
			System.out.println("Thread2尝试获得锁：Lock_B");
			synchronized(Test.Lock_B) {
				System.out.println("Thread2获得锁：Lock_B");
//				Test.sleep1s();
			}
			System.out.println("Thread2：Lock_B释放");
		}
		System.out.println("Thread2：Lock_A释放");
	}
}*/

//wait与notify
/*import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
//一个进程添加String至queue,多个继承读queue中String
public class Test {
	public static void main(String[] args) throws InterruptedException {
		var q = new Task_Queue();// 新建TaskQueue实例对象
		var ts = new ArrayList<Thread>();// 存放线程的数组
		// 开启并运行5个线程，每个线程都尝试打印q中的task
		for (int i = 0; i < 8; i++) {
			ts.add(new Thread(() -> {
				// 执行task:
				while (true) {
					try {
						String s = q.getTask();
						System.out.println(Thread.currentThread().getName()+" get "+s);
					} catch (InterruptedException e) {
						return;
					}
				}
			}));
		}
		ts.forEach((t)->t.start());//		ts.forEach(Thread::start);
		
		// 新建一个add1线程，在线程中，共10次每隔100ms，往q中添加一个String
		var add1 = new Thread(() -> {
			for (int i = 0; i < 10; i++) {
				// 放入task:
				String s = "t-" + Math.random();
				System.out.println(Thread.currentThread().getName()+" add "+s);
				q.addTask(s);
				// 这里每次往q中添加一个String后暂停100ms的原因是为了让上述5个线程中的某一个能够及时捕捉到，并打印
				try {
					Thread.sleep(500);
				} catch (InterruptedException e) {
				}
			}
		});
		add1.start();// 开始执行add1线程，并等待add1执行完毕
		add1.join();// 这里是main线程等待add1线程执行完毕，但是5个getTask线程是在一直运行中
		Thread.sleep(600);// 主线程暂停100ms,目的是留出一点时间,让上述5个线程能够将q中的String全部get出来,然后再对所有的线程提出中断请求

//		ts.forEach(Thread::interrupt);
		ts.forEach((t)->t.interrupt());
	}
}

//class Task_Queue {//wait  notify
//	Queue<String> queue = new LinkedList<>();// LinkedList继承Queue接口
////    Queue<String> queue = new ArrayList<>();//ArrayList没有继承Queue接口，不能使用
//
//	public synchronized void addTask(String s) {
//		this.queue.add(s);// 从队列尾部部增加一个元素，可能超过了队列的容量，它会抛出异常
//		this.notifyAll();
//	}
//
//	public synchronized String getTask() throws InterruptedException {
//		while (queue.isEmpty()) {
//			// 释放this锁,等待唤醒，唤醒后执行wait()后面语句，此处会跳出循环
//			this.wait();// 当一个线程在this.wait()等待时，它就会释放this锁，从而使得其他线程能够在addTask()方法获得this锁。
//			// notify()方法重新获得this锁
//		}
//		return queue.remove();// 从队列头部取一个元素，如队列为空则抛出异常
//	}
//}
class Task_Queue {//await() ReentrantLock  Condition
	//new ReentrantLock()默认为非公平锁
	//new ReentrantLock(true)为表示公平锁，即先请求，先获得。符合FIFO原则
	//new ReentrantLock(false)为表示非公平锁
	private final Lock lock =new ReentrantLock(true);
	private final Condition condition=lock.newCondition();
	private Queue<String> queue = new LinkedList<>();// LinkedList继承Queue接口

	public void addTask(String s) {
		lock.lock();
		try {
			queue.add(s);// 从队列尾部部增加一个元素，可能超过了队列的容量，它会抛出异常
		    condition.signalAll();
		}finally {
			lock.unlock();
		}
	}

	public String getTask() throws InterruptedException {
		lock.lock();
		try {
			while (queue.isEmpty()) {
				condition.await();
			}
			return queue.remove();// 从队列头部取一个元素，如队列为空则抛出异常
		}finally {
			lock.unlock();
		}
	}
}
*/

//两个线程交替打印数字、字母
/*class Print{
	private int flag=1;
	private int count=1;
	public synchronized void printNum() {
		if (flag==2) {
			try {
				this.wait();//会释放当前的锁，然后让出CPU，进入等待状态。只有当notify/notifyAll被执行时候，才会唤醒一个或多
				//个正处于等待状态的线程，然后继续往下执行，直到执行完synchronized代码块的代码或是中途遇到wait() ，再次释放锁。
			}catch(InterruptedException e) {}
		}
		System.out.print(count);
		flag=2;
		this.notify();//notify/notifyAll的执行只是唤醒沉睡的线程，而不会立即释放锁，必须执行完notify()方法所在的synchronized
		              //代码块后才释放。所以在编程中，尽量在使用了notify/notifyAll()后立即退出临界区。
	}
	public synchronized void printChar() {
		if (flag == 1) {
			try {
				this.wait();
			}catch (InterruptedException e) {}
		}
		System.out.print((char)(count-1+'A'));
		count++;
		flag=1;
		this.notify();
	}
}

public class Test{
	public static void main (String[] args) throws InterruptedException {
		Print print=new Print();
		
		new Thread(()->{
			for(int i=0;i<26;i++) {
				print.printChar();
			}
		}).start();

		new Thread(()->{
			for(int i=0;i<26;i++) {
				print.printNum();
			}
		}).start();
	}
}*/

//用多线程实现连续的1,2,1,2,1,2,1,2,1,2输出。

/*class NumberPrint implements Runnable{
	private int number;
	public byte res[];
	public static int count = 10;
	public NumberPrint(int number, byte a[]){
		this.number = number;
		res = a;
	}
	public void run(){
		synchronized (res){
			while(count-- > 0){
				try {
					res.notify();//唤醒等待res资源的线程，把锁交给线程（该同步锁执行完毕自动释放锁）
					System.out.println(count+" "+number);
					res.wait();//释放CPU控制权，释放res的锁，本线程阻塞，等待被唤醒。
					System.out.println("------线程"+Thread.currentThread().getName()+"获得锁，wait()后的代码继续运行："+number);
				} catch (InterruptedException e) {
					//e.printStackTrace();
				}
				
			}//end of while
			return;
		}//synchronized
		
	}
}
public class Test {
	public static void main(String args[]) throws InterruptedException {
		final byte a[] = {0};//以该对象为共享资源
		var t1=new Thread(new NumberPrint(1,a),"1");
		t1.start();
		var t2=new Thread(new NumberPrint(2,a),"2");
		t2.start();
		Thread.sleep(100);
		t1.interrupt();
		t2.interrupt();
		System.out.println("main over");
	}
}*/

/*下面解释为什么会出现这样的结果：
首先1、2号线程启动，这里假设1号线程先运行run方法获得资源（实际上是不确定的），获得对象a的锁，进入while循环（用于控制输出几轮）：
1、此时对象调用它的唤醒方法notify()，意思是这个同步块执行完后它要释放锁，把锁交给等待a资源的线程；
2、输出1；
3、该对象执行等待方法，意思是此时此刻起拥有这个对象锁的线程（也就是这里的1号线程）释放CPU控制权，释放锁，并且线程进入阻塞状态，后面的代码暂时不执行，
   因未执行完同步块，所以1也没起作用；
4、在这之前的某时刻线程2运行run方法，但苦于没有获得a对象的锁，所以无法继续运行，但3步骤之后，它获得了a的锁，此时执行a的唤醒方法notify(),同理，
   意思是这个同步块执行完后它要释放锁，把锁交给等待a资源的线程；
5、输出2；
6、执行a的等待方法，意思是此时此刻起拥有这个对象锁的线程（也就是这里的2号线程）释放CPU控制权，释放锁，并且线程进入阻塞状态，后面的代码暂时不执行，因未
   执行完同步块，所以2号线程的4步骤的唤醒方法也没起作用；
7、此时1号线程执行到3步骤，发现对象锁没有被使用，所以继续执行3步骤中wait方法后面的代码，于是输出：------线程1获得锁，wait()后的代码继续运行：1；
8、此时while循环满足条件，继续执行，所以，再执行1号线程的唤醒方法，意思是这个同步块执行完后它要释放锁；
9、输出1；
10、执行等待方法，线程1阻塞，释放资源锁；
11、此时线程2又获得了锁，执行到步骤6，继续执行wait方法后面的代码，所以输出：------线程2获得锁，wait()后的代码继续运行：2；
12、继续执行while循环，输出2；

··· ···

通过上述步骤，相信大家已经明白这两个方法的使用了，但该程序还存在一个问题，当while循环不满足条件时，肯定会有线程还在等待资源，所以主线程一直
不会终止。当然这个程序的目的仅仅为了给大家演示这两个方法怎么用。
总结：
  wait()方法与notify()必须要与synchronized(resource)一起使用。也就是wait与notify针对已经获取了resource锁的线程进行操作，
从语法角度来说就是Obj.wait(),Obj.notify必须在synchronized(Obj){...}语句块内。从功能上来说wait()线程在获取对象锁后，主动释放CPU控
制权，主动释放对象锁，同时本线程休眠。直到有其它线程调用对象的notify()唤醒该线程，才能继续获取对象锁，并继续执行。相应的notify()就是对对象锁
的释放操作。【因此，我们可以发现，wait和notify方法均可释放对象的锁，但wait同时释放CPU控制权，即它后面的代码停止执行，线程进入阻塞状态，
而notify方法不立刻释放CPU控制权，而是在相应的synchronized(){}语句块执行结束，再自动释放锁。】释放锁后，JVM会在等待resoure的线程中选
取一线程，赋予其对象锁，唤醒线程，继续执行。这样就提供了在线程间同步、唤醒的操作。Thread.sleep()与Object.wait()二者都可以暂停当前线程，
释放CPU控制权，主要的区别在于Object.wait()在释放CPU同时，释放了对象锁的控制，而在同步块中的Thread.sleep()方法并不释放锁，仅释放CPU控制权。
*/
//import java.util.concurrent.locks.ReentrantLock;
//import java.util.concurrent.locks.Lock;
//public class ReentrantLockTest {
/*public class Test {
	public static void main(String[] args) {

		MyService service = new MyService();

		MyThread a1 = new MyThread(service);
		MyThread a2 = new MyThread(service);
		MyThread a3 = new MyThread(service);
		MyThread a4 = new MyThread(service);
		MyThread a5 = new MyThread(service);

		a1.start();
		a2.start();
		a3.start();
		a4.start();
		a5.start();

	}

	static public class MyService {

		private Lock lock = new ReentrantLock();

		public void testMethod() {
			lock.lock();
			try {
				for (int i = 0; i < 5; i++) {
					System.out.println("ThreadName=" + Thread.currentThread().getName() + (" " + (i + 1)));
				}
			} finally {
				lock.unlock();
			}

		}

	}

	static public class MyThread extends Thread {

		private MyService service;

		public MyThread(MyService service) {
			super();
			this.service = service;
		}

		@Override
		public void run() {
			service.testMethod();
		}
	}
}
*/
/*import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.Lock;
public class Test{
	private Lock lock=new ReentrantLock();
	public static void main(String[] args) throws InterruptedException{
		Test test1=new Test();
		
		MyThread thread0=new MyThread(test1);
		MyThread thread1=new MyThread(test1);
		MyThread thread2=new MyThread(test1);
		thread0.start();
		thread1.start();
		thread2.start();
		Thread.sleep(1000);
		thread1.interrupt();
	}
	public void insert(Thread thread) throws InterruptedException{
		lock.lockInterruptibly();
		try {
			System.out.println(thread.getName()+" 得到了锁");
			Thread.sleep(1500);
		}finally{
			System.out.println(thread.getName()+" 释放了锁");
			lock.unlock();
		}
	}
	static public class MyThread extends Thread {
		private Test test;
		public MyThread(Test test) {
			this.test=test;
		}
		
		public void run(){
			try {
				test.insert(Thread.currentThread());
			}catch(InterruptedException e){
				System.out.println(Thread.currentThread().getName()+" 被中断");
			}
		}
	}
}*/
/*import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
public class Test{
	public static void main(String[] args) throws InterruptedException {
		MyService service=new MyService();
		ThreadA a=new ThreadA(service);
		a.start();
		Thread.sleep(1000);
		service.signal_1();
	}
	static public class MyService {
		private Lock lock=new ReentrantLock();
		public Condition condition=lock.newCondition();
		public void await_1() {
			lock.lock();
			try {
				System.out.println("start await...");
				condition.await();
				System.out.println("end await...");
			}catch(InterruptedException e) {
				e.printStackTrace();
			}finally {
				lock.unlock();
			}
		}
		public void signal_1() {
			lock.lock();
			try {
				System.out.println("start signal...");
				condition.signal();
				Thread.sleep(3000);
				System.out.println("end signal...");
			}catch(InterruptedException e) {
				e.printStackTrace();
			}finally {
				lock.unlock();
			}
		}
	}
	static public class ThreadA extends Thread{
		private MyService service;
		public ThreadA(MyService service) {
			this.service=service;
		}
		public void run() {
			service.await_1();
		}
	}
}
*/

/*public class Test{
	public static void main(String[] args) {
		final Test test=new Test();
		new Thread(()->test.get(Thread.currentThread())).start();
		new Thread(()->test.get(Thread.currentThread())).start();
	}
	synchronized public void get(Thread thread) {
		long start=System.currentTimeMillis();
		while (System.currentTimeMillis()-start <=0.000001) {
			System.out.println(thread.getName()+" 正在运行");
		}
		System.out.println(thread.getName() + "读操作完毕");
	}
}*/
/*import java.util.concurrent.locks.ReentrantReadWriteLock;
public class Test{
	ReentrantReadWriteLock rwl=new ReentrantReadWriteLock();
	public static void main(String[] args) {
		final Test test=new Test();
		new Thread(()->test.get(Thread.currentThread())).start();
		new Thread(()->test.get(Thread.currentThread())).start();
	}
	public void get(Thread thread) {
		rwl.readLock().lock();;
		try {
			long start=System.currentTimeMillis();
			while((System.currentTimeMillis()-start)<=0.00001) {
				System.out.println(thread.getName()+" 正在运行");
			}
			System.out.println(thread.getName() + "读操作完毕");
		}finally {
			rwl.readLock().unlock();
		}
	}
}*/

/*import java.util.concurrent.locks.ReentrantReadWriteLock;
public class Test{
	public static void main(String[] args) {
		Service service=new Service();
		//读读共享   两个线程可以同时或者说是几乎同时运行lock()方法后面的代码，输出的两句话显示的时间一样，这样提高了程序的运行效率。
		//MyThread1 t1=new MyThread1(service);//读
		//MyThread1 t2=new MyThread1(service);//读
		
		//写写互斥
		//同一时间只允许一个线程执行lock()方法后面的代码。
		//MyThread2 t1=new MyThread2(service);//写
		//MyThread2 t2=new MyThread2(service);//写
		
		//读写互斥
		//运行两个使用同一个Service对象实例的线程a,b，线程a执行上面的read方法，线程b执行上面的write方法。你会发现同一时间只允许一个线程
		//执行lock()方法后面的代码。
		MyThread1 t1=new MyThread1(service);//读
		MyThread2 t2=new MyThread2(service);//写
		
		t1.start();
		t2.start();
	}
	static public class Service {
		ReentrantReadWriteLock lock=new ReentrantReadWriteLock();
		public void read() {
			lock.readLock().lock();
			try {
				System.out.println(Thread.currentThread().getName()+" 正在读... "+System.currentTimeMillis());
				Thread.sleep(5000);
			}catch(InterruptedException e) {
				e.printStackTrace();
			}
			finally {
				lock.readLock().unlock();
			}
		}
		
		public void write() {
			lock.writeLock().lock();
			try {
				System.out.println(Thread.currentThread().getName()+" 正在写... "+System.currentTimeMillis());
				Thread.sleep(5000);
			}catch(InterruptedException e) {
				e.printStackTrace();
			}
			finally {
				lock.writeLock().unlock();
			}
		}
	}
	static public class MyThread1 extends Thread{
		private Service service;
		public MyThread1(Service service) {
			this.service=service;
		}
		public void run() {
			service.read();
		}
	}
	
	static public class MyThread2 extends Thread{
		private Service service;
		public MyThread2(Service service) {
			this.service=service;
		}
		public void run() {
			service.write();
		}
	}
}*/
/*
import java.util.stream.IntStream;
import java.util.List;

public class Test {
	public static void main(String[] args) {
		System.out.println("abc" == "abc");
		System.out.println("abc" == "abcd".substring(0, 3));// false
		System.out.println("abc".equals("abcd".substring(0, 3)));// true
		List<Integer> list = List.of(12, 34, 56);
		Integer[] array = list.toArray(new Integer[4]);
		for (Integer n : array) {
			System.out.println(n);
		}
		IntStream.range(0, 5).boxed().map(i -> new Thread(() -> System.out.println(Thread.currentThread().getName())))
				.forEach(Thread::start);
	}
}*/


//Volatile关键字能够在并发条件下，强制将修改后的值刷新到主内存中来保持内存的可见性。通过 CPU内存屏障禁止编译器指令性重排来保证并发操作的有序性
//如果多个线程同时操作 Volatile 修饰的变量，也会造成数据的不一致。
//事实上运行它会发现每次运行结果都不一致，都是一个小于10000的数字。
/*
public class Test {
	public volatile int inc = 0;

	public synchronized void increase() {//结果10000
	//public void increase() {//结果<10000
		inc++;
	}

	public static void main(String[] args) {
		final Test test = new Test();
		for (int i = 0; i < 10; i++) {//10个线程运行increase()加1，1000次，正确结果应该是10000.
			new Thread() {
				public void run() {
					for (int j = 0; j < 1000; j++)
						test.increase();
				};
			}.start();
		}
		//public static int activeCount() 它返回当前线程的线程组中活动线程的数量。
		while (Thread.activeCount() > 1){
			System.out.println(Thread.currentThread ().getThreadGroup ().getName());
			System.out.println(Thread.activeCount());
			Thread.yield();//使当前线程处于就绪状态，所有线程（包括当前线程）随机获得运行权。
			}
		System.out.println(test.inc);//结果，小于10000
	}
}
*/

//下面通过例子来说明对象锁：
//定义一个类，方法如下，将 count 自减，从 5 到 0：
/*
class TestSynchronized {
    public synchronized void minus() {
        int count = 5;
        for (int i = 0; i < 5; i++) {
            count--;
            System.out.println(Thread.currentThread().getName() + " - " + count);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
            }
        }
    }
}

//测试调用方法如下：

public class Test {
    public static void main(String[] args) {
        final TestSynchronized test = new TestSynchronized();
        new Thread(new Runnable() {
            @Override
            public void run() {
                test.minus();
            }
        }).start();;

        new Thread(new Runnable() {
            @Override
            public void run() {
                test.minus();
            }
        }).start();
        //thread1.start();
        //thread2.start();
    }
}*/
//两个线程 thread1 和 thread2，同时访问对象的方法，由于该方法是 synchronized 关键字修饰的，那么这两个线程都需要获得该对象锁，一个获得后另一个线程必须
//等待。所以我们可以猜测运行结果应该是，一个线程执行完毕后，另一个线程才开始执行，运行例子，输出打印结果如下：
public class Test {//打印顺序可以肯定是main线程先打印start，t线程再打印hello，main线程最后再打印end。
   public static void main(String[] args) throws InterruptedException {
       Thread t = new Thread(() -> {
           System.out.println("hello");
       });
       System.out.println("start");
       t.start();
       t.join();
       System.out.println("end");
   }
}
